home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / ASSEMBLE / 2593.ZIP / ID12.ZIP / ID.C < prev    next >
C/C++ Source or Header  |  1990-02-16  |  21KB  |  878 lines

  1. /*
  2. **    I N T E L L I G E N T   D I S A S S E M B L E R
  3. **
  4. ** Edit history:
  5. **    16/02/90 OM 1.2    Fixed word offset problem, segment problem in same
  6. **            Prepared for posting to comp.binaries.ibm.pc
  7. **    late  87 OM 1.1    Slight fixes for public release
  8. **    late  86 OM 1.0    Initial release for own use
  9. */
  10.  
  11. char progname[]="id";
  12. char program[]=    "Intelligent Disassembler V1.2";
  13. char copyright[]=
  14.     "(c) 1986,87,88,89,90 by Otto J. Makela, Jyvaskyla, Finland\n"
  15.     "This program is distributed under the GNU General Public License\n"
  16.     "terms.  See the file COPYING for details\n\n"
  17.     "Call JyBox +358 41 211 562, V.22bis/V.22/V.21 24h/day\n\n";
  18.  
  19. #include    <stdio.h>
  20.  
  21.     /* Some compiler-independent types */
  22. #define    BYTE    unsigned char
  23. #define    WORD    unsigned int
  24. #define    SBYTE    signed char
  25. #define    SWORD    signed int
  26.  
  27. #define    ISPRINT(c)    ((c)>=' ' && (c)<='~' && (c)!='\'')
  28. #define    MIN(a,b)    ((a)<(b)?(a):(b))
  29.  
  30.     /* 8086 instruction groups (and statuses) as returned by disasm() */
  31. #define    ERROR        0
  32. #define    DATABYTE    1
  33. #define    IMPLIED        2
  34. #define    ACCIMMED    3
  35. #define    MEMREGIMMED    4
  36. #define    MEMREGMEMREG    5
  37. #define    RELJUMP16    6
  38. #define    STRING        7
  39. #define    MEMREG        8
  40. #define    REG16        9
  41. #define    INOUT        10
  42. #define    INTERRUPT    11
  43. #define    ESCAPE        12
  44. #define    RETURN        13
  45. #define    RELJUMP8    14
  46. #define    CONDRELJUMP8    15
  47. #define    PREFIX        16
  48. #define    REGIMMED    17
  49. #define    SEGMEMREG    18
  50. #define    ACCMEM        19
  51. #define    SEGREG        20
  52. #define    REGADR        21
  53. #define    SHIFT        22
  54. #define    ACCREG        23
  55. #define    SEGPREFIX    24
  56. #define    IMPLIEDUM    25
  57. #define    CALLREL16    26
  58. #define    MEM32        27
  59. #define    REGMEM32    28
  60. #define    CALLABS32    29
  61. #define    JUMPABS32    30
  62.  
  63. SBYTE    adc[]="ADC",add[]="ADD",and[]="AND",call[]="CALL",cmp[]="CMP",
  64.     dec[]="DEC",inc[]="INC",jmp[]="JMP",mov[]="MOV",or[]="OR",
  65.     pop[]="POP",push[]="PUSH",sbb[]="SBB",sub[]="SUB",test[]="TEST",
  66.     xchg[]="XCHG",xor[]="XOR";
  67.  
  68. struct    {
  69.     WORD    c,cm,rm;
  70.     SBYTE    *mn;
  71.     BYTE    gr;
  72. } *cc,cmd[] = {
  73.     0x0037,0x00FF,0x0000,"AAA",IMPLIED,
  74.     0x0AD5,0xFFFF,0x0000,"AAD",IMPLIED,
  75.     0x0AD4,0xFFFF,0x0000,"AAM",IMPLIED,
  76.     0x003F,0x00FF,0x0000,"AAS",IMPLIED,
  77.  
  78.     0x0014,0x00FE,0x0000,adc,ACCIMMED,
  79.     0x1080,0x38FC,0x0000,adc,MEMREGIMMED,
  80.     0x0010,0x00FC,0x3800,adc,MEMREGMEMREG,
  81.  
  82.     0x0004,0x00FE,0x0000,add,ACCIMMED,
  83.     0x0080,0x38FC,0x0000,add,MEMREGIMMED,
  84.     0x0000,0x00FC,0x3800,add,MEMREGMEMREG,
  85.  
  86.     0x0024,0x00FE,0x0000,and,ACCIMMED,
  87.     0x2080,0x38FC,0x0000,and,MEMREGIMMED,
  88.     0x0020,0x00FC,0x3800,and,MEMREGMEMREG,
  89.  
  90.     0x009A,0x00FF,0x0000,call,CALLABS32,
  91.     0x00E8,0x00FF,0x0000,call,CALLREL16,
  92.     0x18FF,0x38FF,0x0000,call,MEM32,
  93.     0x10FF,0x38FF,0x0000,call,MEMREG,
  94.  
  95.     0x0098,0x00FF,0x0000,"CBW",IMPLIED,
  96.     0x00F8,0x00FF,0x0000,"CLC",IMPLIED,
  97.     0x00FC,0x00FF,0x0000,"CLD",IMPLIED,
  98.     0x00FA,0x00FF,0x0000,"CLI",IMPLIED,
  99.     0x00F5,0x00FF,0x0000,"CMC",IMPLIED,
  100.  
  101.     0x003C,0x00FE,0x0000,cmp,ACCIMMED,
  102.     0x3880,0x38FC,0x0000,cmp,MEMREGIMMED,
  103.     0x0038,0x00FC,0x3800,cmp,MEMREGMEMREG,
  104.     0x00A6,0x00FE,0x0000,cmp,STRING,
  105.  
  106.     0x0099,0x00FF,0x0000,"CWD",IMPLIED,
  107.     0x0027,0x00FF,0x0000,"DAA",IMPLIED,
  108.     0x002F,0x00FF,0x0000,"DAS",IMPLIED,
  109.  
  110.     0x08FE,0x38FE,0x0000,dec,MEMREG,
  111.     0x0048,0x00F8,0x0007,dec,REG16,
  112.  
  113.     0x30F6,0x38FE,0x0000,"DIV",MEMREG,
  114.  
  115.     0x00D8,0x00F8,0x0000,"ESC",ESCAPE,
  116.  
  117.     0x00F4,0x00FF,0x0000,"HLT",IMPLIED,
  118.  
  119.     0x38F6,0x38FE,0x0000,"IDIV",MEMREG,
  120.     0x28F6,0x38FE,0x0000,"IMUL",MEMREG,
  121.  
  122.     0x00E4,0x00F6,0x0008,"IN",INOUT,
  123.  
  124.     0x00FE,0x38FE,0x0000,inc,MEMREG,
  125.     0x0040,0x00F8,0x0007,inc,REG16,
  126.  
  127.     0x00CC,0x00FE,0x0000,"INT",INTERRUPT,
  128.     0x00CE,0x00FF,0x0000,"INTO",IMPLIED,
  129.  
  130.     0x00CF,0x00FF,0x0000,"IRET",RETURN,
  131.  
  132.     0x0077,0x00FF,0x0000,"JA",CONDRELJUMP8,
  133.     0x0073,0x00FF,0x0000,"JAE",CONDRELJUMP8,
  134.     0x0072,0x00FF,0x0000,"JB",CONDRELJUMP8,
  135.     0x0076,0x00FF,0x0000,"JBE",CONDRELJUMP8,
  136.     0x00E3,0x00FF,0x0000,"JCXZ",CONDRELJUMP8,
  137.     0x0074,0x00FF,0x0000,"JE",CONDRELJUMP8,
  138.     0x007F,0x00FF,0x0000,"JG",CONDRELJUMP8,
  139.     0x007D,0x00FF,0x0000,"JGE",CONDRELJUMP8,
  140.     0x007C,0x00FF,0x0000,"JL",CONDRELJUMP8,
  141.     0x007E,0x00FF,0x0000,"JLE",CONDRELJUMP8,
  142.  
  143.     0x00EA,0x00FF,0x0000,jmp,JUMPABS32,
  144.     0x00EB,0x00FF,0x0000,jmp,RELJUMP8,
  145.     0x00E9,0x00FF,0x0000,jmp,RELJUMP16,
  146.     0x28FF,0x38FF,0x0000,jmp,MEM32,
  147.     0x20FF,0x38FF,0x0000,jmp,MEMREG,
  148.  
  149.     0x0075,0x00FF,0x0000,"JNE",CONDRELJUMP8,
  150.     0x0071,0x00FF,0x0000,"JNO",CONDRELJUMP8,
  151.     0x007B,0x00FF,0x0000,"JNP",CONDRELJUMP8,
  152.     0x0079,0x00FF,0x0000,"JNS",CONDRELJUMP8,
  153.     0x0070,0x00FF,0x0000,"JO",CONDRELJUMP8,
  154.     0x007A,0x00FF,0x0000,"JP",CONDRELJUMP8,
  155.     0x0078,0x00FF,0x0000,"JS",CONDRELJUMP8,
  156.  
  157.     0x009F,0x00FF,0x0000,"LAHF",IMPLIED,
  158.  
  159.     0x00C5,0x00FF,0x3800,"LDS",REGMEM32,
  160.     0x008D,0x00FF,0x3800,"LEA",REGADR,
  161.     0x00C4,0x00FF,0x3800,"LES",REGMEM32,
  162.  
  163.     0x00F0,0x00FF,0x0000,"LOCK",PREFIX,
  164.  
  165.     0x00AC,0x00FE,0x0000,"LOD",STRING,
  166.  
  167.     0x00E2,0x00FF,0x0000,"LOOP",CONDRELJUMP8,
  168.     0x00E1,0x00FF,0x0000,"LOOPZ",CONDRELJUMP8,
  169.     0x00E0,0x00FF,0x0000,"LOOPNZ",CONDRELJUMP8,
  170.  
  171.     0x0088,0x00FC,0x3800,mov,MEMREGMEMREG,
  172.     0x00B0,0x00F0,0x0007,mov,REGIMMED,
  173.     0x00A0,0x00FC,0x0000,mov,ACCMEM,
  174.     0x008C,0x20FD,0x1800,mov,SEGMEMREG,
  175.     0x00C6,0x38FE,0x0000,mov,MEMREGIMMED,
  176.     0x00A4,0x00FE,0x0000,mov,STRING,
  177.  
  178.     0x20F6,0x38FE,0x0000,"MUL",MEMREG,
  179.     0x18F6,0x38FE,0x0000,"NEG",MEMREG,
  180.  
  181.     0x0090,0x00FF,0x0000,"NOP",IMPLIED,
  182.  
  183.     0x10F6,0x38FE,0x0000,"NOT",MEMREG,
  184.  
  185.     0x000C,0x00FE,0x0000,or,ACCIMMED,
  186.     0x0880,0x38FC,0x0000,or,MEMREGIMMED,
  187.     0x0008,0x00FC,0x3800,or,MEMREGMEMREG,
  188.  
  189.     0x00E6,0x00F6,0x0008,"OUT",INOUT,
  190.  
  191.     0x008F,0x38FF,0x0000,pop,MEMREG,
  192.     0x0058,0x00F8,0x0007,pop,REG16,
  193.     0x0007,0x00E7,0x0018,pop,SEGREG,
  194.     0x009D,0x00FF,0x0000,"POPF",IMPLIED,
  195.  
  196.     0x30FF,0x38FF,0x0000,push,MEMREG,
  197.     0x0050,0x00F8,0x0007,push,REG16,
  198.     0x0006,0x00E7,0x0018,push,SEGREG,
  199.     0x009C,0x00FF,0x0000,"PUSHF",IMPLIED,
  200.  
  201.     0x10D0,0x38FC,0x0000,"RCL",SHIFT,
  202.     0x18D0,0x38FC,0x0000,"RCR",SHIFT,
  203.  
  204.     0x00F2,0x00FF,0x0000,"REPNZ",PREFIX,
  205.     0x00F3,0x00FF,0x0000,"REPZ",PREFIX,
  206.     
  207.     0x00CA,0x00FE,0x0000,"RETF",RETURN,
  208.     0x00C2,0x00FE,0x0000,"RET",RETURN,
  209.  
  210.     0x00D0,0x38FC,0x0000,"ROL",SHIFT,
  211.     0x08D0,0x38FC,0x0000,"ROR",SHIFT,
  212.  
  213.     0x009E,0x00FF,0x0000,"SAHF",IMPLIED,
  214.  
  215.     0x38D0,0x38FC,0x0000,"SAR",SHIFT,
  216.  
  217.     0x001C,0x00FE,0x0000,sbb,ACCIMMED,
  218.     0x1880,0x38FC,0x0000,sbb,MEMREGIMMED,
  219.     0x0018,0x00FC,0x3800,sbb,MEMREGMEMREG,
  220.  
  221.     0x00AE,0x00FE,0x0000,"SCA",STRING,
  222.  
  223.     0x0026,0x00E7,0x0018,"",SEGPREFIX,
  224.  
  225.     0x20D0,0x38FC,0x0000,"SHL",SHIFT,
  226.     0x28D0,0x38FC,0x0000,"SHR",SHIFT,
  227.  
  228.     0x00F9,0x00FF,0x0000,"STC",IMPLIED,
  229.     0x00FD,0x00FF,0x0000,"STD",IMPLIED,
  230.     0x00FB,0x00FF,0x0000,"STI",IMPLIED,
  231.  
  232.     0x00AA,0x00FE,0x0000,"STO",STRING,
  233.  
  234.     0x002C,0x00FE,0x0000,sub,ACCIMMED,
  235.     0x2880,0x38FC,0x0000,sub,MEMREGIMMED,
  236.     0x0028,0x00FC,0x3800,sub,MEMREGMEMREG,
  237.  
  238.     0x00A8,0x00FE,0x0000,test,ACCIMMED,
  239.     0x00F6,0x38FE,0x0000,test,MEMREGIMMED,
  240.     0x0084,0x00FE,0x3800,test,MEMREGMEMREG,
  241.  
  242.     0x009B,0x00FF,0x0000,"WAIT",IMPLIED,
  243.  
  244.     0x0090,0x00F8,0x0007,xchg,ACCREG,
  245.     0x0086,0x00FE,0x3800,xchg,REGADR,
  246.  
  247.     0x00D7,0x00FF,0x0000,"XLAT",IMPLIEDUM,
  248.  
  249.     0x0034,0x00FE,0x0000,xor,ACCIMMED,
  250.     0x3080,0x38FE,0x0000,xor,MEMREGIMMED,
  251.     0x0030,0x00FC,0x3800,xor,MEMREGMEMREG,
  252.  
  253.     0x0000,0x0000,0x0000,"DB",DATABYTE,
  254.     0,0,0,NULL,0 };
  255.  
  256.     /* Character constants */
  257. #define    BYTEONE    (BYTE *)"1"
  258. #define    BYTHREE    (BYTE *)"3"
  259.  
  260.     /* 8086 registers, and some #define's for them */
  261. SBYTE *regset[2][8] = {    "AL","CL","DL","BL","AH","CH","DH","BH",
  262.             "AX","CX","DX","BX","SP","BP","SI","DI" };
  263. #define    ACC    (BYTE *)regset[word][0]
  264. #define    AX    (BYTE *)regset[1][0]
  265. #define    DX    (BYTE *)regset[1][2]
  266. #define    CL    (BYTE *)regset[0][1]
  267. SBYTE *segreg[4] = {    "ES","CS","SS","DS" };
  268.  
  269.     /* Addressing modes, BYTE/WORD PTR overrides */
  270. SBYTE *adrmod[8] = {    "[BX+SI]","[BX+DI]","[BP+SI]","[BP+DI]",
  271.             "[SI]","[DI]","[BP]","[BX]" };
  272. SBYTE *bytwrd[3] = {    "BYTE","WORD","DWORD" };
  273.  
  274.     /* Command output formats */
  275. SBYTE *oper[] = { "\t%s", "\t%s\t%s", "\t%s\t%s,%s" };
  276. #define    NULOP    oper[0]
  277. #define    ONEOP    oper[1]
  278. #define    TWOOP    oper[2]
  279.  
  280.     /* Some functions */
  281. BYTE *index(),*getmod(),*fmtcon(),*fmtadr(),disasm();
  282.  
  283.     /* Scratch area, code and reference tables (each 64kbits of length) */
  284. #define    B64k    (64/8*1024)
  285.     BYTE scratch[80],code[B64k],refd[B64k];
  286.     /* General bit handling macros */
  287. #define    SETBIT(a,b)    (a[b>>3] |= (1<<(b&7)))
  288. #define    TSTBIT(a,b)    (a[b>>3] & (1<<(b&7)))
  289.     /*
  290.     ** "Is code" means we try to dissassemble it.  "Is referenced"
  291.     ** means we need a label on the line and we guess at data offsets.
  292.     */
  293. #define    SETCODE(i)    SETBIT(code,i)
  294. #define    SETREFD(i)    SETBIT(refd,i)
  295. #define    ISCODE(i)    TSTBIT(code,i)
  296. #define    ISREFD(i)    TSTBIT(refd,i)
  297.  
  298.     /* Standard start offset for .COM-files */
  299. #define    ADJUST    0x100
  300. WORD adjust=ADJUST;
  301.     /* Device driver flag */
  302. WORD devdriver=0;
  303.  
  304.  
  305. main(argc,argv)
  306. int argc;
  307. BYTE *argv[];    {
  308.     register BYTE c;
  309.     register WORD i;
  310.     BYTE quote,filename[80];
  311. #define    MAXENTRY    100
  312. #define    MAXEXIT        40
  313.     WORD j,baseadr,address,data;
  314.     WORD entrypts[MAXENTRY],exitpts[MAXEXIT],entrys=0,exits=0;
  315.     union    {
  316.         WORD x;
  317.         BYTE h[2];
  318.     } regtrace[8];
  319.     WORD regdefd=0;
  320. #define    REGISTER    (word? regtrace[i].x: regtrace[i>>2].h[i&1])
  321. #define    SETDEFINED    regdefd|=(word? 3<<(2*reg): 1<<(2*reg+4) )
  322.     FILE *f,*g;
  323.  
  324.     *argv=(BYTE *)progname;
  325.     fprintf(stderr,"%s - %s, compiled "__DATE__"\n%s",*argv,
  326.         program,copyright);
  327.     if(argc<2)    {
  328.         fprintf(stderr,"usage: %s prog[.com] [@cmdfile] [=adjust] "
  329.             "[[+]entry]] [-exit] [:addr] [~]...\n",*argv);
  330.         exit(0);
  331.     }
  332.  
  333.     strcpy(filename,argv[1]);
  334.     if(!index(filename,'.'))
  335.         strcat(filename,".com");
  336.     if(!(f=fopen((char *)filename,"r")))    {
  337.         fprintf(stderr,"%s: file \"%s\" not found\n",*argv,filename);
  338.         exit(1);
  339.     }
  340.  
  341.     for(i=0; i<B64k; i++) code[i]=refd[i]=0;
  342.  
  343.     g=NULL;
  344.     do    {
  345.         for(i=2; i<argc; i++)    {
  346.             if(!index("0123456789ABCDEFabcdef",c=*argv[i]))
  347.                 argv[i]++;
  348.             else
  349.                 c='+';
  350.             if(c!='@' && c!='~' &&
  351.                 sscanf(argv[i],"%x",&address)!=1)    {
  352.                 fprintf(stderr,"%s: illegal hexadecimal offset \"%s\" - "
  353.                     "ignored\n",*argv,argv[i]);
  354.                 continue;
  355.             }
  356.             switch(c)    {
  357.             case '+':
  358.                 entrypts[entrys++]=address;
  359.                 /* Flow thru */
  360.             case ':':
  361.                 SETREFD(address);
  362.                 break;
  363.             case '-':
  364.                 exitpts[exits++]=address;
  365.                 break;
  366.             case '=':
  367.                 adjust=address;
  368.                 break;
  369.             case '@':
  370.                 if(g) fclose(g);
  371.                 if(!(g=fopen((char *)argv[i],"r")))
  372.                     fprintf(stderr,"%s: cannot open file \"%s\"\n",
  373.                         *argv,argv[i]);
  374.                 break;
  375.             case '~':
  376.                 devdriver = !devdriver;
  377.                 break;
  378.             default:
  379.                 fprintf(stderr,"%s: unknown option '%c' - ignored\n",*argv,c);
  380.                 break;
  381.             }
  382.         }
  383.     } while(g && fgets(argv[(argc=3)-1]=scratch,sizeof(scratch),g));
  384.     if(g) fclose(g);
  385.  
  386.         /* Device driver - ignore header for now */
  387.     if(devdriver)    {
  388.         adjust = 0;
  389.         fread(scratch,sizeof(BYTE),6,f);
  390.         fread(&j,sizeof(WORD),1,f);
  391.         entrypts[entrys++]=j; SETREFD(j);
  392.         fread(&j,sizeof(WORD),1,f);
  393.         entrypts[entrys++]=j; SETREFD(j);
  394.         SETREFD(4);
  395.         SETREFD(6);
  396.         SETREFD(8);
  397.         SETREFD(0xA);
  398.     }
  399.  
  400.     SETREFD(adjust);
  401.     if(!entrys)
  402.         entrypts[entrys++]=adjust;
  403.  
  404.     fprintf(stderr,  "entr");
  405.     for(i=0; i<entrys; i++)
  406.         fprintf(stderr," %04x",entrypts[i]);
  407.     fprintf(stderr,"\nexit");
  408.     for(i=0; i<exits; i++)
  409.         fprintf(stderr," %04x",exitpts[i]);
  410.     if(!exits)
  411.         fprintf(stderr," none\n");
  412.     else
  413.         fprintf(stderr,"\n");
  414.  
  415.     fprintf(stderr,"%s: pass one\n",*argv);
  416.  
  417. nextentry:
  418.     while(entrys)    {
  419.         baseadr=entrypts[--entrys];
  420. nextcomm:    if(ISCODE(baseadr)) continue;
  421.         if((c=disasm(f,baseadr,&address,0,&data))==ERROR ||
  422.             c==DATABYTE) continue;
  423.         for(;address--; baseadr++)
  424.             SETCODE(baseadr);
  425.         switch(c)    {
  426.         case MEMREGIMMED:
  427.         case REGADR:
  428.         case MEMREGMEMREG:
  429.         case MEMREG:
  430.         case ESCAPE:
  431.         case SEGMEMREG:
  432.         case ACCMEM:
  433.         case SHIFT:
  434.         case REGMEM32:
  435.         case MEM32:
  436.             if(data)
  437.                 SETREFD(data);
  438.             break;
  439.         case CALLREL16:
  440.         case CONDRELJUMP8:
  441.             if(!ISCODE(baseadr))
  442.                 entrypts[entrys++]=baseadr;
  443.             /* Flow thru */
  444.         case RELJUMP16:
  445.         case RELJUMP8:
  446.             SETREFD(data);
  447.             baseadr=data;
  448.             break;
  449.         case INTERRUPT:
  450.             if(data!=0x20 && data!=0x27) break;
  451.         case RETURN:
  452.             goto nextentry;
  453.         }
  454.         for(i=0; i<exits; i++)
  455.             if(baseadr==exitpts[i])    {
  456.                 while(++i<exits)
  457.                     exitpts[i-1]=exitpts[i];
  458.                 exits--;
  459.                 goto nextentry;
  460.             }
  461.         goto nextcomm;
  462.     }
  463.  
  464.     fprintf(stderr,  "code");
  465.     for(i=0; i<0xFFFF; i++)
  466.         if(ISCODE(i))    {
  467.             fprintf(stderr," %04x-",i);
  468.             while(i<0xFFFF && ISCODE(i)) i++;
  469.             fprintf(stderr,"%04x",i-1);
  470.         }
  471.     fprintf(stderr,"\nrefs");
  472.     for(i=0; i<0xFFFF; i++)
  473.         if(ISREFD(i))
  474.             fprintf(stderr," %04x",i);
  475.     fprintf(stderr,"\n");
  476.  
  477.     fprintf(stderr,"%s: pass two\n",*argv);
  478.     printf("\tTITLE\t%s - produced by %s\n",filename,program);
  479.     printf("CSEG\tSEGMENT\n");
  480.     printf("\tASSUME\tCS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG\n");
  481.     printf("\tORG\t%s\n",fmtcon(adjust,scratch,0));
  482.     baseadr=adjust;
  483. skip:    if(!ISCODE(baseadr))    {
  484.         quote=0; i=75; j=0; address=1;
  485.         while(!ISCODE(baseadr))    {
  486.             if(address>=j)    {
  487.                 if(fseek(f,(long)(baseadr-adjust),0) ||
  488.                     !(j=fread(scratch,sizeof(BYTE),
  489.                     sizeof(scratch),f)))    {
  490.                     if(quote)
  491.                         putchar('\'');
  492.                     putchar('\n');
  493.                     goto thend;
  494.                 }
  495.                 address=0;
  496.             }
  497.             if(i>=75 || ISREFD(baseadr))    {
  498.                 if(quote)
  499.                     putchar('\'');
  500.                 quote=0;
  501.                 putchar('\n');
  502.                 if(ISREFD(baseadr))
  503.                     printf("LB%04X",baseadr);
  504.                 if(ISPRINT(c=scratch[address]))    {
  505.                     printf("\tDB\t'%c",c);
  506.                     quote=1;
  507.                     i=18;
  508.                 } else    {
  509.                     printf("\tDB\t%3d",c);
  510.                     i=19;
  511.                 }
  512.                 baseadr++;
  513.                 address++;
  514.             }
  515.             while(address<j && i<75 && !ISCODE(baseadr) &&
  516.                 !ISREFD(baseadr))    {
  517.                 if(ISPRINT(c=scratch[address]))
  518.                     if(quote)    {
  519.                         putchar(c);
  520.                         i++;
  521.                     } else    {
  522.                         printf(",'%c",c);
  523.                         quote=1;
  524.                         i+=3;
  525.                     }
  526.                 else    {
  527.                     if(quote)    {
  528.                         putchar('\'');
  529.                         quote=0;
  530.                         i++;
  531.                     }
  532.                     printf(",%3d",c);
  533.                     i+=4;
  534.                 }
  535.                 address++;
  536.                 baseadr++;
  537.             }
  538.         }
  539.         if(quote)
  540.             putchar('\'');
  541.         putchar('\n');
  542.     }
  543.     if(ISREFD(baseadr))
  544.         printf("LB%04X:",baseadr);
  545.     if(disasm(f,baseadr,&address,1,&data)<=DATABYTE)
  546.         goto thend;
  547.     baseadr+=address;
  548.     goto skip;
  549. thend:    printf("CSEG\tENDS\n");
  550.     printf("\tEND\tLB%04X\n",adjust);
  551.     fclose(f);
  552. }
  553.  
  554.  
  555. /*
  556. **    Disassemble bytes from file f at address, based at baseadr
  557. **    If display is true, print the instructions
  558. */
  559.  
  560. #define    Dprintf    if(display) printf
  561.  
  562. BYTE disasm(f,baseadr,address,display,data)
  563. FILE *f;
  564. WORD baseadr,*address;
  565. register WORD *data;
  566. BYTE display;    {
  567.     BYTE word,dir,pass;
  568.     BYTE *p,mem[10];
  569.     /* MEM is a WORD, Smem a SBYTE, and SMEM a SWORD - all in mem[] */
  570. #define    MEM(i)    (*((WORD  *)(mem+i)))
  571. #define    Smem(i)    (*((SBYTE *)(mem+i)))
  572. #define    SMEM(i)    (*((SWORD *)(mem+i)))
  573.     static BYTE *seg=NULL;
  574.     WORD reg,loop;
  575.     register WORD i;
  576.     SWORD s;
  577.  
  578.     if(fseek(f,(long)(baseadr-adjust),0)) return ERROR;
  579.     if(!fread(mem,sizeof(BYTE),sizeof(mem),f)) return ERROR;
  580.  
  581.     *address=0;
  582. again:    for(loop=0; (cc=cmd+loop)->mn; loop++)
  583.         if((MEM(*address) & cc->cm)==cc->c)    {
  584.             word=mem[*address]&1;
  585.             if(cc->cm & 2)
  586.                 dir=0;
  587.             else
  588.                 dir=(mem[*address]&2)>>1;
  589.             if(i=cc->rm)
  590.                 for(reg=MEM(*address) & i; !(i&1); i>>=1)
  591.                     reg>>=1;
  592.             (*address)++;
  593.             switch(cc->gr)    {
  594.             case IMPLIED:
  595.                 Dprintf(NULOP,cc->mn);
  596.                 if(cc->cm&0xFF00) (*address)++;
  597.                 break;
  598.             case ACCIMMED:
  599.                 if(word)
  600.                     i=MEM(1);
  601.                 else
  602.                     i=mem[1];
  603.                 Dprintf(TWOOP,cc->mn,ACC,
  604.                     fmtcon(i,scratch,6+word));
  605.                 *address+=1+word;
  606.                 break;
  607.             case MEMREGIMMED:
  608.                 p=getmod(mem,address,word,&seg,data);
  609.                 if(dir)
  610.                     s=Smem(*address);
  611.                 else if(word)
  612.                     s=MEM(*address);
  613.                 else
  614.                     s=mem[*address];
  615.                 Dprintf(TWOOP,cc->mn,p,
  616.                     fmtcon(s,scratch,6+word));
  617.                 (*address)++;
  618.                 if(!dir && word) (*address)++;
  619.                 break;
  620.             case REGMEM32:
  621.                 word=2;
  622.                 /* Flow thru ! */
  623.             case REGADR:
  624.                 dir=1;
  625.                 /* Flow thru ! */
  626.             case MEMREGMEMREG:
  627.                 p=getmod(mem,address,word,&seg,data);
  628.                 if(display) if(dir)
  629.                     printf(TWOOP,cc->mn,regset[MIN(1,word)][reg],p);
  630.                 else
  631.                     printf(TWOOP,cc->mn,p,regset[MIN(1,word)][reg]);
  632.                 break;
  633.             case CALLREL16:
  634.             case RELJUMP16:
  635.                 i=SMEM(*address);
  636.                 *address+=2;
  637.                 *data=*address+i+baseadr;
  638.                 Dprintf("\t%s\tLB%04X",cc->mn,*data);
  639.                 break;
  640.             case STRING:
  641.                 if(display) if(seg)    {
  642.                     printf("%sS\t%s",cc->mn,fmtadr(adjust,
  643.                         word,scratch,&seg));
  644.                     seg=NULL;
  645.                 } else
  646.                     printf("\t%sS%c",cc->mn,word?'W':'B');
  647.                 break;
  648.             case MEM32:
  649.                 word=2;
  650.                 /* Flow thru ! */
  651.             case MEMREG:
  652.                 p=getmod(mem,address,word,&seg,data);
  653.                 Dprintf(ONEOP,cc->mn,p);
  654.                 break;
  655.             case ESCAPE:
  656.                 i=((0x07&mem[0])<<3)|((0x38&mem[1])>>3);
  657.                 p=getmod(mem,address,word,&seg,data);
  658.                 Dprintf(TWOOP,cc->mn,fmtcon(i,scratch,0),p);
  659.                 break;
  660.             case REG16:
  661.                 Dprintf(ONEOP,cc->mn,regset[1][reg]);
  662.                 break;
  663.             case INOUT:
  664.                 if(reg)
  665.                     p=DX;
  666.                 else
  667.                     p=fmtcon((WORD)mem[(*address)++],
  668.                         scratch,0);
  669.                 if(display) if(dir)
  670.                     printf(TWOOP,cc->mn,p,ACC);
  671.                 else
  672.                     printf(TWOOP,cc->mn,ACC,p);
  673.                 break;
  674.             case INTERRUPT:
  675.                 if(word)
  676.                     p=fmtcon(*data=mem[(*address)++],
  677.                         scratch,0);
  678.                 else    {
  679.                     p=BYTHREE;
  680.                     *data=3;
  681.                 }
  682.                 Dprintf(ONEOP,cc->mn,p);
  683.                 break;
  684.             case RETURN:
  685.                 if(word)    {
  686.                     Dprintf(NULOP,cc->mn);
  687.                 } else    {
  688.                     Dprintf(ONEOP,cc->mn,fmtcon
  689.                         (MEM(*address),scratch,0));
  690.                     *address+=2;
  691.                 }
  692.                 break;
  693.             case CONDRELJUMP8:
  694.             case RELJUMP8:
  695.                 *data=baseadr+2+Smem((*address)++);
  696.                 Dprintf("\t%s\tSHORT LB%04X",cc->mn,*data);
  697.                 break;
  698.             case PREFIX:
  699.                 Dprintf(NULOP,cc->mn);
  700.                 goto again;
  701.             case SEGPREFIX:
  702.                 seg=(BYTE *)segreg[reg];
  703.                 goto again;
  704.             case REGIMMED:
  705.                 word=(mem[0]&8)>>3;
  706.                 if(word)
  707.                     i=MEM(1);
  708.                 else
  709.                     i=mem[1];
  710.                 Dprintf(TWOOP,cc->mn,regset[word][reg],
  711.                     fmtcon(i,scratch,7));
  712.                 *address+=1+word;
  713.                 break;
  714.             case SEGMEMREG:
  715.                 p=getmod(mem,address,word=1,&seg,data);
  716.                 if(display) if(dir)
  717.                     printf(TWOOP,cc->mn,segreg[reg],p);
  718.                 else
  719.                     printf(TWOOP,cc->mn,p,segreg[reg]);
  720.                 break;
  721.             case ACCMEM:
  722.                 *data=MEM(*address);
  723.                 if(display) if(dir)
  724.                     printf(TWOOP,cc->mn,fmtadr(*data,word,
  725.                         scratch,&seg),ACC);
  726.                 else
  727.                     printf(TWOOP,cc->mn,ACC,fmtadr(*data,
  728.                         word,scratch,&seg));
  729.                 *address+=2;
  730.                 break;
  731.             case SEGREG:
  732.                 Dprintf(ONEOP,cc->mn,segreg[reg]);
  733.                 break;
  734.             case SHIFT:
  735.                 p=getmod(mem,address,word,&seg,data);
  736.                 Dprintf(TWOOP,cc->mn,p,dir?CL:BYTEONE);
  737.                 break;
  738.             case ACCREG:
  739.                 Dprintf(TWOOP,cc->mn,AX,regset[1][reg]);
  740.                 break;
  741.             case IMPLIEDUM:
  742.                 Dprintf(ONEOP,cc->mn,
  743.                     fmtadr(adjust,word=0,scratch,&seg));
  744.                 break;
  745.             case CALLABS32:
  746.             case JUMPABS32:
  747.                 Dprintf("\t%s\t%04X:%04X",cc->mn,
  748.                     MEM(*address+2),MEM(*address));
  749.                 *address+=4;
  750.                 break;
  751.             case DATABYTE:
  752.                 Dprintf(ONEOP,cc->mn,fmtcon
  753.                     ((WORD)mem[*address],scratch,2));
  754.                 break;
  755.             }
  756.             break;
  757.         }
  758.     Dprintf("\n");
  759.     return cc->gr;
  760. }
  761.  
  762.  
  763. /*
  764. **    Handle a mod/rm field
  765. */
  766.  
  767. BYTE *getmod(mem,addrp,word,seg,data)
  768. WORD *addrp,*data;
  769. BYTE mem[],word,**seg;    {
  770.     static BYTE result[30];
  771.     register BYTE mod,rm;
  772.     SBYTE disp;
  773.     BYTE *p=result;
  774.  
  775.     *data=0;
  776.     mod=(mem[*addrp]>>6)&3;
  777.     rm=mem[(*addrp)++]&7;
  778.     switch(mod)    {
  779.     case 3:
  780.         return (BYTE *) regset[word][rm];
  781.     case 2:
  782.         if((*data=MEM(*addrp))>adjust && adjust)
  783.             fmtadr(*data,word,result,seg);
  784.         else    {
  785.             if(*seg)    {
  786.                 while(**seg) *p++=*(*seg)++;
  787.                 *p++=':';
  788.                 *p++=' ';
  789.                 *seg=NULL;
  790.             }
  791.             fmtcon(*data,p,0);
  792.             *data=0;
  793.             strcat(p,adrmod[rm]);
  794.         }
  795.         *addrp+=2;
  796.         return result;
  797.     case 1:
  798.         disp=Smem((*addrp)++);
  799.         if(*seg)    {
  800.             sprintf(result,"%s PTR %s:%d%s",bytwrd[word],*seg,
  801.                 disp,adrmod[rm]);
  802.             *seg=NULL;
  803.         } else
  804.             sprintf(result,"%s PTR %d%s",bytwrd[word],disp,
  805.                 adrmod[rm]);
  806.         return result;
  807.     case 0:
  808.         if(rm!=6)    {
  809.             if(*seg)    {
  810.                 sprintf(result,"%s PTR %s:%s",bytwrd[word],
  811.                     *seg,adrmod[rm]);
  812.                 *seg=NULL;
  813.             } else
  814.                 sprintf(result,"%s PTR %s",bytwrd[word],
  815.                     adrmod[rm]);
  816.             return result;
  817.         }
  818.         fmtadr(*data=MEM(*addrp),word,result,seg);
  819.         *addrp+=2;
  820.         return result;
  821.     }
  822. }
  823.  
  824.  
  825. /*
  826. **    Format constant value to string where:
  827. **    type&1 -    value can be a label offset
  828. **    type&2 -    value can be a character which should be followed by
  829. **            a comment giving it's ASCII code
  830. **    type&4 -    value could be interpreted as negative
  831. */
  832.  
  833. BYTE *fmtcon(value,where,type)
  834. WORD value,type;
  835. BYTE *where;    {
  836.     BYTE *p=where;
  837.     SWORD i=(SWORD)value;
  838.  
  839.     if(type&1 && value>=adjust && adjust && ISREFD(value))
  840.         sprintf(where,"OFFSET LB%04X",value);
  841.     else    {
  842.         if(type&4 && i<0 && i>=-128)    {
  843.             *p++='-';
  844.             value=i=-i;
  845.         }
  846.         if(value<10)    {
  847.             *p++=value+'0';
  848.             *p='\0';
  849.         } else
  850.             sprintf(p,"0%xh",value);
  851.         if(type&2 && ISPRINT(value))    {
  852.             char cc[3];
  853.             strcat(p,"\t\t; '");
  854.             cc[0]=value; cc[1]='\''; cc[2]='\0';
  855.             strcat(p,cc);
  856.         }
  857.     }
  858.     return where;    
  859. }
  860.  
  861.  
  862. /*
  863. **    Format an address to string
  864. */
  865.  
  866. BYTE *fmtadr(value,word,where,seg)
  867. WORD value;
  868. BYTE word,*where,**seg;    {
  869.     BYTE *p;
  870.  
  871.     if(*seg)    {
  872.         sprintf(where,"%s PTR %s:LB%04X",bytwrd[word],*seg,value);
  873.         *seg=NULL;
  874.     } else
  875.         sprintf(where,"%s PTR LB%04X",bytwrd[word],value);
  876.     return where;    
  877. }
  878.